
#if defined(WIN32) || defined(WIN64)
#pragma unmanaged
#endif

#include <Liberty3D/Engine/Win32Exception.h>
#include <Liberty3D/Engine/Conversion.h>
#include <Liberty3D/Engine/Window.h>

#include "ErrorStrings.h"

using namespace Liberty::Engine;

HINSTANCE Window::hInstance = NULL;

static std::string ToError(DWORD err, DWORD stringID) {
    std::string s;
    LPWSTR neutral    = NULL;
    LPWSTR local      = NULL;
    LPWSTR fullString = NULL;
    WCHAR  ec[512];
    WCHAR  w [1024];

    FormatMessage(
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        err,
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        (LPWSTR)&local,
        0,
        NULL);

    FormatMessage(
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_ALLOCATE_BUFFER,
        NULL,
        err,
        MAKELANGID(LANG_ENGLISH, SUBLANG_DEFAULT),
        (LPWSTR)&neutral,
        0,
        NULL);

    fullString = new wchar_t[4096];

    if (Window::hInstance == NULL) {
        Window::hInstance = GetModuleHandle(NULL);
    }

    LoadString(Window::hInstance, stringID,       w,  _countof(w));
    LoadString(Window::hInstance, IDS_ERROR_CODE, ec, _countof(ec));
    swprintf_s(fullString, 4096, ec, w, err, local, neutral);

    if (neutral) {
        LocalFree(neutral);
    }

    if (local) {
        LocalFree(local);
    }

    s = UTF16_To_UTF8(fullString);
    delete [] fullString;
    return s;
}

Win32Exception::Win32Exception(DWORD errorCode) : std::runtime_error(ToError(errorCode, IDS_ERROR_UNKNOWN)), _errorCode(errorCode) {
}

Win32Exception::Win32Exception(DWORD errorCode, UINT uID) : std::runtime_error(ToError(errorCode, uID)), _errorCode(errorCode) {
}
